class Promise {
  constructor(callback) {
    this.state = 'pending';
    this.value = null;
    this.reason = null;
    this.onResolveCallbacks = [];
    this.onRejectCallbacks = [];
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'resolve';
        this.value = value;
        this.onResolveCallbacks.forEach(fn => fn());
      }
    };
    let reject = reason => {
      if (this.state === 'pending') {
        this.state = 'reject';
        this.reason = reason;
        this.onRejectCallbacks.forEach(fn => fn());
      }
    };
    try {
      callback(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onResolve, onReject) {
    onResolve = typeof onResolve === 'function' ? onResolve : value => value;
    onReject = typeof onReject === 'function' ? onReject : err => { throw err };
    let promise2 = new Promise((resolve, reject) => {
      if (this.state === 'pending') {
        this.onResolveCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onResolve(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onReject(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
      if (this.state === 'resolve') {
        setTimeout(() => {
          try {
            let x = onResolve(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.state === 'reject') {
        setTimeout(() => {
          try {
            let x = onReject(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
    });
    return promise2;
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  let called;
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(x, y => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          if (called) return;
          called = true;
          reject(err);
        })
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
module.exports = Promise;